<?php
/*
 * 作者: Ryan
 * QQ: 541720500
 * Email: 541720500@qq.com
 */

namespace JkPHP;

use function FastRoute\simpleDispatcher;
use Medoo\Medoo;
use Pimple\Container;
use FastRoute\RouteCollector;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

class Boot
{
    // 容器
    static $container;

    // 定义根目录
    static $root_path = __DIR__ . '/../';

    // 配置
    static $config;

    // 模型名
    static $module;

    // 控制器名
    static $controller;

    // 方法名
    static $action;

    function __construct()
    {
        // 加载配置
        Config::load();

        // 来一个容器 https://pimple.symfony.com/
        self::$container = new Container();

        // 容器里的db是默认链接 想改变链接，需要使用 new \JkPHP\Db($new_config) 或 db($new_config)
        self::$container['db'] = function ($c) {
            return new Medoo(Boot::$config['database']);
        };

        // 模板引擎
        self::$container['view'] = function ($c) {
            $loader = new FilesystemLoader(Boot::$root_path . 'app/' . Boot::$module . '/v');
            return new Environment($loader, [
                'debug' => Boot::$config['debug'],
                'cache' => Boot::$root_path . 'temp/swig',
            ]);
        };

        // 进入公共函数
        require_once 'helper.php';
    }

    // 主运行函数
    function go()
    {
        Route::dispatch();
    }
}

class Model
{
    public $db;

    public function __construct($config = [])
    {
        if (empty($config))
            $this->db = Boot::$container['db'];
        else {
            $this->db = new Medoo(array_merge(Boot::$config['database'], $config));// 新配置替换默认配置
        }
    }

    function db($config = [])
    {
        $this->db = db($config);
        return $this->db;
    }
}

class Controller
{
    public $vars = [];

    function db($config = [])
    {
        return db($config);
    }

    // 控制器赋值
    function assign($key, $value)
    {
        $this->vars[$key] = $value;
    }

    // 模板显示
    function display($file_name = null)
    {

        $view = Boot::$container['view'];
        $temp_file = $file_name !== null ? $file_name : Boot::$controller . DIRECTORY_SEPARATOR . Boot::$action . '.html';
        echo $view->render($temp_file, $this->vars);

    }
}

class Config
{
    // 默认配置
    static $default = [
        'debug' => true,
        'default_mca_name' => 'index',
        'default_controller_dir' => 'c',
        'default_view_dir' => 'v',
        'default_model_dir' => 'm',
    ];

    public static function load()
    {
        $config_file = Boot::$root_path . 'app' . DIRECTORY_SEPARATOR . 'config.php';
        if (!is_file($config_file)) {
            throw new \Exception('未设置配置文件');
        }
        $config = require_once $config_file;

        Boot::$config = array_merge(self::$default, $config);
    }
}

class Route
{
    public static function dispatch()
    {
        $dispatcher = simpleDispatcher(function (RouteCollector $r) {
            $route_file = Boot::$root_path . 'app' . DIRECTORY_SEPARATOR . 'route.php';
            if (!is_file($route_file)) {
                throw new \Exception('未设置路由文件');
            }
            $route_arr = require_once $route_file;
            foreach ($route_arr as $k => $v) {
                $r->addRoute($v[0], $v[1], $v[2]);
                if (!is_numeric($k)) {
                    foreach ($v as $g) {
                        $r->addGroup('/' . $k, function (RouteCollector $r) use ($g) {
                            $r->addRoute($g[0], $g[1], $g[2]);
                        });
                    }
                }
            }
        });
        $httpMethod = $_SERVER['REQUEST_METHOD'];
        $uri = $_SERVER['REQUEST_URI'];
        if (false !== $pos = strpos($uri, '?')) {
            $uri = substr($uri, 0, $pos);
        }
        $uri = rawurldecode($uri);

        $routeInfo = $dispatcher->dispatch($httpMethod, $uri);
        switch ($routeInfo[0]) {
            case \FastRoute\Dispatcher::NOT_FOUND:
                throw new \Exception("... 404 Not Found 没找到对应的方法");
                break;
            case \FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
                $allowedMethods = $routeInfo[1];
                throw new \Exception("... 405 Method Not Allowed 方法不允许");
                break;
            case \FastRoute\Dispatcher::FOUND: // 找到对应的方法
                $handler = $routeInfo[1]; // 获得处理函数
                $vars = $routeInfo[2]; // 获取请求参数
                self::readyGetController($handler, $vars);
                break;
            default:
                throw new \Exception('Route Error : not dispatch');
        }
    }

    private static function readyGetController($handler, $vars)
    {
        $config = Boot::$config;
        $handler_arr = explode('/', $handler);
        $module = $handler_arr[0] ?: $config['default_mca_name'];
        $controller = $handler_arr[1] ?? $config['default_mca_name'];
        $action = $handler_arr[2] ?? $config['default_mca_name'];

        Boot::$module = strtolower($module);
        Boot::$controller = strtolower($controller);
        Boot::$action = strtolower($action);

        $namespace_path = 'app\\' . strtolower($module) . '\\' . $config['default_controller_dir'] . '\\' . ucfirst($controller);
        $get_controller = new $namespace_path();
        $get_controller->$action($vars);
    }
}
